#pragma once

#include <compl.h>

#include <dcont/dprompt.h>

/* 参考s_task设置的语法糖 */
#define __async__	prompt_t *__prompt__
#define __await__	(__prompt__)

/* 基于multi-prompt实现的协程 */
typedef struct corou {
	struct{
		prompt_t	prm;
		size_t		stk_size;
		word_t		cols[];	/* 对齐剩余的空间可以做协程私有存储区 */
	} CACHE_ALIGNED;
} corou_t;

typedef void*	(crout_int_alloc_t)	(size_t size, size_t *real_size);
typedef void	(crout_int_free_t)	(void *ptr, size_t size);

PSAI size_t corou_sizeof_cols(){ return sizeof(corou_t) - sizeof(prompt_t) - sizeof(size_t); }

SAI void *corou_get_mblk(corou_t *c){
	void *ptr;
	if (HDEF_STK_GROWS_DOWNWARD){
		ptr = (void *)((paddr_t)c + sizeof(corou_t) - c->stk_size);
	}else{
		ptr = (void *)((paddr_t)c);
	}

	return ptr;
}
/* corou可以在栈上分配 */
SAI corou_t *corou_init(void *ptr, size_t stk_size, ipromptf_t *fp, word_t arg, promptf_t *start_func){
	corou_t *c;
	/* 栈是向下增长的 */
	//void *stk_ptr;
	if (HDEF_STK_GROWS_DOWNWARD){
		c = (corou_t *)((paddr_t)ptr + stk_size - sizeof(corou_t));
		//stk_ptr = (void *)(stksize_align((word_t)(ptr + stk_size - sizeof(corou_t) - PROMPT_STK_RESERVED_SIZE)));
	}
	else{
		c = (corou_t *)ptr;
		//stk_ptr = (void *)(stksize_align((word_t)(ptr + sizeof(corou_t) + PROMPT_STK_RESERVED_SIZE)));
	}
	prompt_thinit();
	__prompt_init(&c->prm);
	// c->prm.func_ptr = fp;
	c->prm.cofun_ptr = fp;
	c->prm.ret_arg = arg;
	c->stk_size = stk_size;
	// c->mblk_ptr = ptr;

	/* 尝试执行并记录当前恢复点 */
	if (start_func)prompt_exec(&c->prm, start_func, (word_t)c);
	
	return c;
}

#define corou_yield(pcorou, targ)	\
	({corou_t *__c = (pcorou); word_t carg = (targ); prompt_yield_v(&(__c->prm), carg); })

#define corou_resume(pcorou, targ)   \
	({corou_t *__c = (pcorou); word_t carg = (targ); prompt_resume_v(&(__c->prm), carg); })


// #define corou_reset(pcorou, wrapper_func)	  ({corou_t *__c = (pcorou); if(wrapper_func) prompt_exec(&(__c->prm), (wrapper_func), (word_t)__c);})

#define corou_firstexec(pcorou)	 

/* 处理空间申请 */
SAI corou_t *__corou_create(size_t stk_size, ipromptf_t *fp, word_t arg, 
	crout_int_alloc_t *crout_int_alloc, promptf_t *wrapper_func){
	size_t real_size;
	void *ptr = crout_int_alloc(stk_size, &real_size);
	if (!ptr) return NULL_PTR;
	return corou_init(ptr, real_size, fp, arg, wrapper_func);
}

SAI void __corou_release(corou_t *c, crout_int_free_t *crout_int_free){
	void *mptr = corou_get_mblk(c);
	crout_int_free(mptr, c->stk_size);
}


#define DEF_COROU_ALLOC(name, int_alloc, int_free, start_func)						  \
SAI corou_t * name##_corou_create(size_t stk_size, ipromptf_t *fp, word_t arg){ \
	return __corou_create(stk_size, fp, arg, int_alloc, start_func); } \
SAI void name##_corou_release(corou_t *c){ __corou_release(c, int_free); } 
